package Library;

import java.awt.event.*;

/**
 * Blocked Waiting Object which waits till it receives a result.
 * @param <T>
 */
public class WaitableObject<T>
{
    /**
     *
     */
    protected ActionListener m_Listener;
    private final Object m_CanWaitMutex = new Object();
    private boolean m_CanWait = true;
    private javax.swing.Timer m_Timer;
    private boolean m_Expired = false;

    private boolean m_ResultSet = false;
    private final Object m_ResultMutex = new Object();
    private T m_Result;
    
    /**
     *
     * @return
     */
    public T getResult()
    {
	T result;
	synchronized (m_ResultMutex)
	{
	    result = m_Result;
	}
	return result;
    }
    
    /**
     *
     * @param result
     * @return
     */
    public boolean setResult(T result)
    {
	boolean res;
	synchronized (m_ResultMutex)
	{
	    res = !m_ResultSet; 
	    if (res)
	    {
		m_Result = result;
		m_ResultSet = true;
	    }
	}
	return res;
    }
    
    private boolean hasSetOrExpired()
    {
	boolean result;
	synchronized (m_ResultMutex)
	{
	    result = m_ResultSet || m_Expired;
	}
	return result;
    }
    
    /**
     *
     * @param time
     * @param listener
     * @return
     */
    public boolean wait(int time, ActionListener listener)
    {
	boolean res;
 	synchronized (m_CanWaitMutex)
	{
	    res = m_CanWait;
	    if (res)
	    {
		m_ResultSet = false;
		m_Expired = false;
	    }
	}
	if (!res)
	    return false;
	
	m_Listener = listener;
	m_CounterMax = time;
	m_Counter = time;
	//m_Timer = new javax.swing.Timer(1000, timerElapsed);
	//m_Timer.setRepeats(true);
	//m_Timer.start();
	    
	while (!hasSetOrExpired())
	{
	    try
	    {
		actionPerformed(new ActionEvent(new Object(), 1, "waitable_object"));
		Thread.sleep(1000);
	    }
	    catch (InterruptedException ex)
	    {
		// Shouldn't suppose to happen
		ex.printStackTrace();
	    }
	}
	
 	synchronized (m_CanWaitMutex)
	{
	    m_CanWait = true;
	}
	return true;
    }
    
    /**
     *
     */
    protected int m_CounterMax;
    /**
     *
     */
    protected int m_Counter;
    /**
     *
     */
    //protected ActionListener timerElapsed = new ActionListener()
    //{
	public void actionPerformed(ActionEvent e)
	{
	    System.out.println("Waiting Timer: " + m_CounterMax + "/" + m_Counter);
	    m_Counter--;
	    if (m_Counter == 0)
	    {
		//m_Timer.stop();
		synchronized (m_ResultMutex)
		{
		    m_Expired = true;
		    System.out.println("Waiting Timer Expired!");
		}
	    }
	    
	    if (m_Listener != null)
	    {
		m_Listener.actionPerformed(new WaitableObjectEvent(e.getID(), 
			e.getActionCommand(), e.getWhen(), e.getModifiers(), m_Counter, m_CounterMax));
	    }
	}
    //};
}
